/**
 * @author casazaft
 */
Package("j2j.dom").Class("QueryBuilder", {
    QueryBuilder: function(){
        this.cache = new j2j.utils.HashMap();
        var wRe = /^(#)?(\w+)/;
        var oRe = /^(\s?[\/>+~]\s?|\s|$)/;
        var trimRe = /^\s+|\s+$/g;
        var travelId = function(root, id, result){
            if (!root.firstChild) 
                return result;
            var child = root.firstChild;
            while (child) {
                if (child.id == id) 
                    result.push(child);
                travelId(child, id, result);
                child = child.nextSibling;
            }
        };
        var byId = function(ns, mode, root, id){
            var result = [];
            if (!mode) {
                if (root.getElementById) {
                    result[result.length] = root.getElementById(id);
                }
                else {
                    travelId(root, id, result);
                }
                return result;
            }
            else {
                return this.getNodes(ns, mode, id);
            }
        };
        var getNodes = function(root, mode, id){
            var cs, ri = -1;
            var result = [];
            if (!root) {
                return result;
            }            
            result[0] = document.getElementById(id);                        
            return result;            
        };
        
        var byTag = function(root, op, tag){        
            var result = [];
            var cs, ri = -1;
            if (!root) {
                root = [document];
            }
            if (root.getElementsByTagName) 
                root = [root];
            var utag = tag.toUpperCase();
            if (!op) {
                for (var i = 0, ni; ni = root[i]; i++) {
                    cs = ni.getElementsByTagName(tag);
                    for (var j = 0, ci; ci = cs[j]; j++) {
                        result[++ri] = ci;
                    }
                }
            }
            else {
                switch (op) {
                    case ' ':{
                        for (var i = 0, ni; ni = root[i]; i++) {
                            cs = ni.getElementsByTagName(tag);
                            for (var j = 0, ci; ci = cs[j]; j++) {
                                result[++ri] = ci;
                            }
                        }
                        break;
                    }
                    case '>':{
                        var utag = tag.toUpperCase();
                        for (var i = 0, ni, cn; ni = root[i]; i++) {
                            cn = ni.children || ni.childNodes;
                            for (var j = 0, cj; cj = cn[j]; j++) {
                                if (cj.nodeName == utag || cj.nodeName == tag) {
                                    result[++ri] = cj;
                                }
                            }
                        }
                        break;
                    }
                    case '+':{
                        var utag = tag.toUpperCase();
                        for (var i = 0, n; n = root[i]; i++) {
                            while ((n = n.nextSibling) && n.nodeType != 1) 
                                ;
                            if (n && (n.nodeName == utag || n.nodeName == tag)) {
                                result[++ri] = n;
                            }
                        }
                        break;
                    }
                    
                }
                
            }
            return result;
            
        }
        
        this.compile = function(str){
            var classRef = this.getClass();
            var fn = ['var fun =function(root){\nvar n,mode;\nroot=root||document;\n']
            for (var match, mode; match = str.match(wRe);) {
                if (match[1] == "#") {
                    fn.push('n=byId(n,mode,root,"' + match[2] + '");\n');
                }
                else {
                    fn.push('n=byTag(n,mode,"' + match[2] + '");\n');
                }
                str = str.replace(match[0], "");
                mode = str.match(oRe);
                if (mode[1]) {
                    if (mode[1] != " ") 
                        mode[1] = mode[1].replace(trimRe, "");
                    fn.push('mode="' + mode[1] + '";\n');
                    str = str.replace(mode[0], "");
                }
            }
            fn.push('return n;\n};');
            fn = fn.join("");
            eval(fn);
            return fun;
        };
        
        
    },
    Extends: "j2j.patterns.Singleton"
});
